﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.ComponentModel;
using MockupDesigner.Editors;
using MockupDesigner.Items;
using MockupDesigner.AppItems.Controls;
using MockupDesigner.AppItems.Commands;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using MockupDesigner.Items.Metadatas;

namespace MockupDesigner.AppItems
{
    //These attributes identify the types of the named parts that are used for templating
    [TemplatePart(Name = "PART_DragThumb", Type = typeof(DragThumb))]
    [TemplatePart(Name = "PART_ResizeDecorator", Type = typeof(Control))]
    [TemplatePart(Name = "PART_ContentPresenter", Type = typeof(ContentPresenter))]
    public class DesignerItem : ContentControl, ISelectable, IGroupable
    {
        #region ID
        private Guid id;
        public Guid ID
        {
            get { return id; }
        }
        #endregion

        #region ParentID
        public Guid ParentID
        {
            get { return (Guid)GetValue(ParentIDProperty); }
            set { SetValue(ParentIDProperty, value); }
        }
        public static readonly DependencyProperty ParentIDProperty = DependencyProperty.Register("ParentID", typeof(Guid), typeof(DesignerItem));
        #endregion

        #region IsGroup
        public bool IsGroup
        {
            get { return (bool)GetValue(IsGroupProperty); }
            set { SetValue(IsGroupProperty, value); }
        }
        public static readonly DependencyProperty IsGroupProperty =
            DependencyProperty.Register("IsGroup", typeof(bool), typeof(DesignerItem));
        #endregion

        #region ISelectable Properties

        public bool IsSelected
        {
            get { return (bool)GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); }
        }
        public static readonly DependencyProperty IsSelectedProperty =
          DependencyProperty.Register("IsSelected",
                                       typeof(bool),
                                       typeof(DesignerItem),
                                       new FrameworkPropertyMetadata(false));

        #endregion

        #region DragThumbTemplate Property

        // can be used to replace the default template for the DragThumb
        public static readonly DependencyProperty DragThumbTemplateProperty =
            DependencyProperty.RegisterAttached("DragThumbTemplate", typeof(ControlTemplate), typeof(DesignerItem));

        public static ControlTemplate GetDragThumbTemplate(UIElement element)
        {
            return (ControlTemplate)element.GetValue(DragThumbTemplateProperty);
        }

        public static void SetDragThumbTemplate(UIElement element, ControlTemplate value)
        {
            element.SetValue(DragThumbTemplateProperty, value);
        }

        #endregion

        public bool IsInToolbox
        {
            get { return (bool)GetValue(IsInToolboxProperty); }
            set { SetValue(IsInToolboxProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsInToolbox.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsInToolboxProperty =
            DependencyProperty.Register("IsInToolbox", typeof(bool), typeof(DesignerItem), new UIPropertyMetadata(false));



        public bool Resizable
        {
            get
            {
                return this.Content != null && (this.Content is ResizableItem || !(this.Content is ItemBase)); // For Shape which are not null and not Itembase
            }
        }

        //for example : when the text of a checkBox changes, resize it. (item not resizable)
        protected override void OnContentChanged(object oldContent, object newContent)
        {
            base.OnContentChanged(oldContent, newContent);
            if (!(newContent is ResizableItem))
            {
                FrameworkElement content = newContent as FrameworkElement;
                if (content != null)
                    content.SizeChanged += new SizeChangedEventHandler(content_SizeChanged);
            }
            this.SizeChanged += new SizeChangedEventHandler(DesignerItem_SizeChanged);
        }

        void content_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            this.Height = e.NewSize.Height;
            this.Width = e.NewSize.Width;
            ReloadPropertyGrid();
        }

        private static DesignerService designerService = new DesignerService();

        static DesignerItem()
        {
            // set the key to reference the style for this control
            FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(
                typeof(DesignerItem), new FrameworkPropertyMetadata(typeof(DesignerItem)));
        }

        public DesignerItem(Guid id)
        {
            this.id = id;
            this.Loaded += new RoutedEventHandler(DesignerItem_Loaded);
            this.SizeChanged += new SizeChangedEventHandler(DesignerItem_SizeChanged);
        }

        void DesignerItem_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (Resizable)
            {
                FrameworkElement c = this.Content as FrameworkElement;
                if (c != null)
                {
                    c.Height = e.NewSize.Height;
                    c.Width = e.NewSize.Width;
                    ReloadPropertyGrid();
                }
            }
            else
            {
                (this.Template.FindName("PART_ResizeDecorator", this) as Control).Height = (sender as FrameworkElement).ActualHeight;
                (this.Template.FindName("PART_ResizeDecorator", this) as Control).Width = (sender as FrameworkElement).ActualWidth;
            }
        }

        public void ReloadPropertyGrid()
        {
            DesignerCanvas canvas = this.Parent as DesignerCanvas;
            if (canvas == null)
                return;
            canvas.PropertyGrid.SelectedObject = null;
            canvas.PropertyGrid.SelectedObject = this.Content;
            if (this.Content is IMetadatable)
            {
                canvas.MetadataControl.SetMetadatable((IMetadatable)this.Content);
            }
        }

        public DesignerItem()
            : this(Guid.NewGuid())
        {
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            base.OnKeyDown(e);
            if (e.Key == Key.F2)
            {
                ShowEditor();
            }

            if (e.Key != Key.Up && e.Key != Key.Down && e.Key != Key.Left && e.Key != Key.Right)
                return;

            DesignerCanvas dc = (DesignerCanvas)VisualTreeHelper.GetParent(this);
            DragCommand dragCommand = new DragCommand();
            dragCommand.SetInitialPositions(dc, this);
            switch (e.Key)
            {
                case Key.Up:
                    dragCommand.SetFinalDelta(0, -1);
                    break;
                case Key.Down:
                    dragCommand.SetFinalDelta(0, 1);
                    break;
                case Key.Left:
                    dragCommand.SetFinalDelta(-1, 0);
                    break;
                case Key.Right:
                    dragCommand.SetFinalDelta(1, 0);
                    break;
            }
            dc.CommandProcessor.ExecuteCommand(dragCommand, dc, null);
        }

        protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
        {
            base.OnPreviewMouseDown(e);
            DesignerCanvas designer = VisualTreeHelper.GetParent(this) as DesignerCanvas;
            // update selection
            if (designer != null)
            {
                if ((Keyboard.Modifiers & (ModifierKeys.Shift | ModifierKeys.Control)) != ModifierKeys.None)
                    if (this.IsSelected)
                    {
                        designer.SelectionService.RemoveFromSelection(this);
                        designer.DataContext = null;
                    }
                    else
                    {
                        designer.SelectionService.AddToSelection(this);
                        designer.DataContext = this;
                    }
                else if (!this.IsSelected)
                {
                    designer.SelectionService.SelectItem(this);
                    designer.DataContext = this;
                }
                Focus();
            }
            e.Handled = false;
        }

        void DesignerItem_Loaded(object sender, RoutedEventArgs e)
        {
            if (base.Template != null)
            {
                ContentPresenter contentPresenter =
                    this.Template.FindName("PART_ContentPresenter", this) as ContentPresenter;
                if (contentPresenter != null)
                {
                    UIElement contentVisual = VisualTreeHelper.GetChild(contentPresenter, 0) as UIElement;
                    if (contentVisual != null)
                    {
                        DragThumb thumb = this.Template.FindName("PART_DragThumb", this) as DragThumb;
                        if (thumb != null)
                        {
                            ControlTemplate template =
                                DesignerItem.GetDragThumbTemplate(contentVisual) as ControlTemplate;
                            if (template != null)
                                thumb.Template = template;
                        }
                    }
                }
            }
        }

        protected override void OnMouseDoubleClick(MouseButtonEventArgs e)
        {
            base.OnMouseDoubleClick(e);
            ShowEditor();
        }

        private void ShowEditor()
        {
            if (this.Content == null || !(this.Content is ItemBase))
                return;
            ItemEditor editor = designerService.GetEditor((ItemBase)this.Content);
            if (editor != null)
            {
                (this.Parent as DesignerCanvas).SetCurrentEditor(editor, Canvas.GetTop(this), Canvas.GetLeft(this));
            }
        }
    }
}
